/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.workflow.rpc.saas;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.je.bpm.model.process.ModelOperatorService;
import com.je.bpm.model.process.results.ProcessModelResult;
import com.je.common.base.DynaBean;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.MetaService;
import com.je.common.base.util.JEUUID;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import com.je.workflow.service.model.ModelService;
import org.apache.servicecomb.provider.pojo.RpcSchema;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RpcSchema(schemaId = "workflowTenantInstallRpcService")
public class WorkflowTenantInstallRpcServiceImpl implements WorkflowTenantInstallRpcService {

    @Autowired
    private MetaService metaService;
    @Autowired
    private CommonService commonService;
    @Autowired
    private ModelService modelService;
    @Autowired
    private ModelOperatorService modelOperatorService;

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void installWorkflowResource(DynaBean tenantBean, DynaBean product, Map<String, List<DynaBean>> resourceMap, Map<String, String> oldNewRoleMap, Map<String, String> oldKeyNewFuncBeanMap) {
        List<DynaBean> workflowDefinitionConfigList = resourceMap.get("definition");
        if (workflowDefinitionConfigList == null || workflowDefinitionConfigList.isEmpty()) {
            return;
        }
        if (oldKeyNewFuncBeanMap == null) {
            oldKeyNewFuncBeanMap = new HashMap<>();
        }
        if (oldNewRoleMap == null) {
            oldNewRoleMap = new HashMap<>();
        }
        List<String> configIdList = new ArrayList<>();
        for (DynaBean eachConfigBean : workflowDefinitionConfigList) {
            configIdList.add(eachConfigBean.getStr("PROZY_ZY_ID"));
        }

        List<DynaBean> workflowList = metaService.select("JE_WORKFLOW_PROCESSINFO", ConditionsWrapper.builder()
                .in("JE_WORKFLOW_PROCESSINFO_ID", configIdList));

        Map<String, String> oldNewRegistry = new HashMap<>();
        String originId;
        String newId;
        for (DynaBean eachDefinitionBean : workflowList) {
            originId = eachDefinitionBean.getStr("JE_WORKFLOW_PROCESSINFO_ID");
            if (oldKeyNewFuncBeanMap.containsKey(originId)) {
                newId = oldKeyNewFuncBeanMap.get(originId);
            } else {
                newId = JEUUID.uuid();
            }
            oldNewRegistry.put(originId, newId);
        }

        ProcessModelResult modelResult;
        ProcessModelResult newModelResult;
        DynaBean metaInfoXMl;
        JSONObject metaInfoJsonObj;
        String newFuncId;
        String newProcessKey;
        for (DynaBean eachDefinitionBean : workflowList) {
            newFuncId = oldKeyNewFuncBeanMap.get(eachDefinitionBean.getStr("PROCESSINFO_FUNC_ID"));
            newProcessKey = JEUUID.uuid();
            if (Strings.isNullOrEmpty(newFuncId)) {
                continue;
            }

            modelResult = modelOperatorService.getModel(eachDefinitionBean.getStr("PROCESSINFO_MODEL_ID"));
            metaInfoXMl = metaService.selectOne("act_ge_bytearray", ConditionsWrapper.builder().eq("ID_", eachDefinitionBean.getStr("PROCESSINFO_RESOURCE_XML_ID")));

            metaInfoJsonObj = JSON.parseObject(modelResult.getEntity().getMetaInfo());
            replaceFuncId(metaInfoJsonObj, oldNewRegistry.get(eachDefinitionBean.getStr("JE_WORKFLOW_PROCESSINFO_ID")), newFuncId,newProcessKey);
            replaceRoleId(metaInfoJsonObj, oldNewRoleMap);
            newModelResult = modelOperatorService.saveModel("", metaInfoJsonObj.toJSONString(), eachDefinitionBean.getStr("PROCESSINFO_FUNC_CODE"));
            metaInfoXMl.set("ID_", JEUUID.uuid());

            metaService.insert(metaInfoXMl);
            modelService.deploy(eachDefinitionBean);

            eachDefinitionBean.set("JE_WORKFLOW_PROCESSINFO_ID", oldNewRegistry.get(eachDefinitionBean.getStr("JE_WORKFLOW_PROCESSINFO_ID")));
            eachDefinitionBean.set("PROCESSINFO_MODEL_ID", newModelResult.getEntity().getId());
            eachDefinitionBean.set("PROCESSINFO_RESOURCE_XML_ID", metaInfoXMl.get("ID_"));
            eachDefinitionBean.set("PROCESSINFO_SAAS_PID", product.getStr("JE_SAAS_PRODUCT_ID"));
            eachDefinitionBean.set("PROCESSINFO_FUNC_ID", newFuncId);
            eachDefinitionBean.set("PROCESSINFO_KEY",newProcessKey);
            eachDefinitionBean.set("SY_TENANT_ID", tenantBean.getStr("JE_SAAS_TENANT_ID"));
            eachDefinitionBean.set("SY_TENANT_NAME", tenantBean.getStr("TENANT_NAME"));
            metaService.insert(eachDefinitionBean);
        }
    }

    /**
     * 替换功能id
     *
     * @param metaInfoJsonObj
     * @param newDefinitionId
     * @param newFuncId
     */
    private void replaceFuncId(JSONObject metaInfoJsonObj, String newDefinitionId, String newFuncId,String newProcessKey) {
        metaInfoJsonObj.getJSONObject("properties").put("JE_WORKFLOW_PROCESSINFO_ID", newDefinitionId);
        metaInfoJsonObj.getJSONObject("properties").getJSONObject("processBasicConfig").put("funcId", newFuncId);
        metaInfoJsonObj.getJSONObject("properties").put("process_id", newProcessKey);
    }

    /**
     * 替换角色
     *
     * @param metaInfoJsonObj
     * @param oldNewRoleIdMap
     */
    private void replaceRoleId(JSONObject metaInfoJsonObj, Map<String, String> oldNewRoleIdMap) {
        if (!metaInfoJsonObj.containsKey("childShapes")) {
            return;
        }
        JSONArray childShapes = metaInfoJsonObj.getJSONArray("childShapes");
        JSONObject eachAssignConfig;
        JSONArray eachResourceArrayObj;
        for (int i = 0; i < childShapes.size(); i++) {
            if (!childShapes.getJSONObject(i).containsKey("assignmentConfig")) {
                continue;
            }
            eachAssignConfig = childShapes.getJSONObject(i).getJSONObject("assignmentConfig");
            if (!eachAssignConfig.containsKey("resource")) {
                continue;
            }
            eachResourceArrayObj = eachAssignConfig.getJSONArray("resource");
            for (int j = 0; j < eachResourceArrayObj.size(); j++) {
                if ("roleConfig".equals(eachResourceArrayObj.getJSONObject(j).getString("type"))) {
                    if (!oldNewRoleIdMap.containsKey(eachResourceArrayObj.getJSONObject(j).get("resourceId"))) {
                        continue;
                    }
                    eachResourceArrayObj.getJSONObject(j).put("resourceId", oldNewRoleIdMap.get(eachResourceArrayObj.getJSONObject(j).get("resourceId")));
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void uninstallWorkflowResource(DynaBean tenantBean, DynaBean product, Map<String, List<DynaBean>> resourceMap) {
        List<DynaBean> processInfoBeanList = metaService.select("JE_WORKFLOW_PROCESSINFO", ConditionsWrapper.builder()
                .eq("PROCESSINFO_SAAS_PID", product.getStr("JE_SAAS_PRODUCT_ID"))
                .eq("SY_TENANT_ID", tenantBean.getStr("JE_SAAS_TENANT_ID")));
        if (processInfoBeanList == null || processInfoBeanList.isEmpty()) {
            return;
        }
        List<String> idList = new ArrayList<>();
        List<String> modelIdList = new ArrayList<>();
        List<String> xmlIdList = new ArrayList<>();
        for (DynaBean eachProcessBean : processInfoBeanList) {
            idList.add(eachProcessBean.getStr("JE_WORKFLOW_PROCESSINFO_ID"));
            modelIdList.add(eachProcessBean.getStr("PROCESSINFO_MODEL_ID"));
            xmlIdList.add(eachProcessBean.getStr("PROCESSINFO_RESOURCE_XML_ID"));
        }

        modelService.unDeploy("JE_WORKFLOW_PROCESSINFO", Joiner.on(",").join(idList));
        metaService.delete("JE_WORKFLOW_PROCESSINFO", ConditionsWrapper.builder()
                .eq("PROCESSINFO_SAAS_PID", product.getStr("JE_SAAS_PRODUCT_ID"))
                .eq("SY_TENANT_ID", tenantBean.getStr("JE_SAAS_TENANT_ID")));
        metaService.executeSql("DELETE FROM act_re_model  WHERE ID_ in ({0})", modelIdList);
        metaService.executeSql("DELETE FROM act_ge_bytearray  WHERE ID_ in ({0})", xmlIdList);
    }

}
